/*
 * Line.cpp
 *
 *  Created on: 05-01-2011
 *      Author: Piotr
 */

#include "geometry/Line.hpp"
#include "utils/MathUtils.hpp"

Line::Line(float x0, float y0, float x1, float y1) :
	start(x0, y0), end(x1, y1)
{
}

Line::Line(const Vector& start, const Vector& end) :
	start(start), end(end)
{

}

Line::SIDE_IN_CCW Line::getSide(const Vector& point) const
{
	float ccw = calculateCCWFactor(point);

	if(ccw < 0.0f)
	{
		return NEGATIVE;
	}

	if(ccw > 0.0f)
	{
		return POSITIVE;
	}

	return ON;
}

float Line::calculateCCWFactor(const Vector& point) const
{
	const Vector& lineDir = end - start;
	Vector pointDir = point - start;
	float ccw = pointDir.getX() * lineDir.getY() - pointDir.getY() * lineDir.getX();
	if(MathUtils::isNearZero(ccw))
	{
		ccw = pointDir.getX() * lineDir.getX() + pointDir.getY() * lineDir.getY();
		if(ccw > 0.0f)
		{
			pointDir -= lineDir;
			ccw = pointDir.getX() * lineDir.getX() + pointDir.getY() * lineDir.getY();
			if(ccw < 0.0f)
			{
				ccw = 0.0f;
			}
		}
	}

	return ccw;
}

const Vector& Line::getStartPoint() const
{
	return start;
}

const Vector& Line::getEndPoint() const
{
	return end;
}

float Line::getSquaredLength() const
{
	return (end - start).getSquaredLength();
}

bool Line::intersects(const Line& line) const
{
	int test1_a = check_tri_clock_dir(start, end, line.getStartPoint());
	int test1_b = check_tri_clock_dir(start, end, line.getEndPoint());
	if(test1_a != test1_b)
	{
		int test2_a = check_tri_clock_dir(line.getStartPoint(), line.getEndPoint(), start);
		int test2_b = check_tri_clock_dir(line.getStartPoint(), line.getEndPoint(), end);
		if(test2_a != test2_b)
		{
			return true;
		}
	}
	return false;
}

int Line::check_tri_clock_dir(const Vector& pt1, const Vector& pt2, const Vector& pt3) const
{
	float test = (((pt2.getX() - pt1.getX()) * (pt3.getY() - pt1.getY()))
			- ((pt3.getX() - pt1.getX()) * (pt2.getY() - pt1.getY())));
	if(test > 0)
		return COUNTER_CLOCKWISE;
	else if(test < 0)
		return CLOCKWISE;
	else
		return LINE;
}

